﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Security;
using Microsoft.MetadirectoryServices;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;

namespace FIM.XMA
{
    public class PowershellUtils
    {

        public Runspace OpenRunSpace(string host, string user, SecureString password)
        {
            string SHELL_URI = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";


            if (string.IsNullOrEmpty(host))
            {
                Runspace myRunSpace = RunspaceFactory.CreateRunspace();

                myRunSpace.Open();

                return myRunSpace;
            }
            else
            {
                //Create credential to use for authentication
                PSCredential credential = CreatePSCredential(user, password);

                //Validate Uri path
                if (!host.ToLower().EndsWith(":5985/wsman")) { host = host + ":5985/wsman"; }
                if (!(host.ToLower().StartsWith("http://") || host.StartsWith("https://"))) { host = "HTTP://" + host; }

                //Create connectionInfo
                Uri serverUri = new Uri(host);
                WSManConnectionInfo connectionInfo = new WSManConnectionInfo(serverUri, SHELL_URI, credential);
                connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default;
                //Create Runspace
                Runspace myRunSpace = RunspaceFactory.CreateRunspace(connectionInfo);

                //Open Runspace
                myRunSpace.Open();

                return myRunSpace;

            }

        }

        public PSCredential CreatePSCredential(string username, SecureString password)
        {
            PSCredential credential = new PSCredential(username, password);
            return credential;
        }

        public void AddPlugins(string plugins, ref Runspace runspace)
        {
            foreach (string plugin in plugins.Split(','))
            {
                PowerShell myPowerShell = PowerShell.Create();
                myPowerShell.Runspace = runspace;
                myPowerShell.AddCommand("Add-PSSnapin");
                myPowerShell.AddParameter("name", plugin);
                myPowerShell.Invoke();
                myPowerShell.Dispose();
            }
        }

        public void AddScriptFromFile(string filename, ref PowerShell powershell)
        {

            using (StreamReader sr = new StreamReader(filename))
            {
                String CmdLet = sr.ReadToEnd();
                powershell.AddScript(CmdLet);
            }

        }

        public bool ExecutePowershell(PowerShell powershell, ref string errorMsg, bool treatWarningsAsError = false)
        {
            ICollection<PSObject> psResults=null;
            return ExecutePowershell(powershell,ref psResults,ref errorMsg,treatWarningsAsError);
        }

        public bool ExecutePowershell(PowerShell powershell, ref ICollection<PSObject> psResults, ref string errorMsg, bool treatWarningsAsError = false)
        {
            try
            {
                //Invoke powershell
                psResults = powershell.Invoke();

                //Check result
                if (powershell.Streams.Error.Count > 0)
                {
                    foreach (ErrorRecord err in powershell.Streams.Error) { errorMsg = "Error : " + err.Exception.Message; }
                    return false;
                }
                if (powershell.Streams.Warning.Count > 0)
                {
                    foreach (WarningRecord warn in powershell.Streams.Warning) { errorMsg = "Warning : " + warn.Message; }
                    if (treatWarningsAsError) { return false; }
                }

                errorMsg = null;
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = ex.Message;
                return false;
            }

        }

        public string resolvePSFileName(string fileName)
        {

            if (string.IsNullOrEmpty(fileName)) { return null; }
            
            string newfile = fileName;
            string extensionDir = Utils.ExtensionsDirectory;

            if (!newfile.EndsWith(".ps1")) { newfile += ".ps1"; }

            if (File.Exists(newfile)) { return newfile; }
            if (File.Exists(extensionDir + @"\" + newfile)) { return extensionDir + @"\" + newfile; }

            return null;
        }

    }

    public class exportEntries
    {
        public void UpdateExportHashTables(CSEntryChange cs,ref string ModificationType,ref string dn,ref Hashtable ChangedAttributes,ref Hashtable AddAttributeValues,ref Hashtable RemovedAttributeValues)
        {
            //Set ModificationType
            ModificationType=cs.ObjectModificationType.ToString();
            dn=cs.DN;

            //Populate ChagedAttributes HashTable
            foreach (string changeAttributeName in cs.ChangedAttributeNames) { ChangedAttributes.Add(changeAttributeName,ModificationType); }
                
            // Add the values to the powershell hashtable
            IList<AttributeChange> changes = cs.AttributeChanges;
            foreach(AttributeChange change in changes)
            {
                ArrayList addValues = new ArrayList();
                ArrayList removeValues = new ArrayList();
                addValues.Clear();
                removeValues.Clear();

                //Add each value and its modification type.
                foreach (ValueChange valueChange in change.ValueChanges)
                {
                    switch (valueChange.ModificationType)
                    {
                        case ValueModificationType.Add:
                            addValues.Add(valueChange.Value.ToString());
                            break;

                        case ValueModificationType.Delete:
                            removeValues.Add(valueChange.Value.ToString());
                            break;

                        default:
                            throw new UnexpectedDataException();
                    }
                }

                if (addValues.Count > 0) { AddAttributeValues.Add(change.Name, addValues); }
                if (removeValues.Count > 0) { RemovedAttributeValues.Add(change.Name, removeValues); }
      
            }

            }
        }

    public class schemaUtils
    {
        public void AddToSchemaFromHashTable(Hashtable hashtable,ref Schema schema)
        {

            string objectType = null;
            object[] attributes = null;
            string attrName = null;
            string attrType = null;
            bool isAnchor = false;
            bool isMultivalued = false;

            foreach (string key in hashtable.Keys)
            {
                switch (key.ToLower())
                {
                    case "objtype": { objectType = hashtable[key].ToString(); break; }
                    case "attributes": { attributes = (object[])hashtable[key]; break;  }
                }
            }

            Microsoft.MetadirectoryServices.SchemaType newObj = Microsoft.MetadirectoryServices.SchemaType.Create(objectType,false);

            foreach (object obj in attributes)
            {
                string[] items = obj.ToString().Split(',');
                foreach (string part in items)
                {
                    switch (part.Split('=')[0])
                    {
                        case "name": { attrName = part.Split('=')[1]; break; }
                        case "type": { attrType = part.Split('=')[1]; break; }
                        case "anchor": { isAnchor = Convert.ToBoolean(part.Split('=')[1]); break; }
                        case "multivalue": { isMultivalued = Convert.ToBoolean(part.Split('=')[1]); break; }
                    }
                }


                switch (attrType.ToLower())
                {
                    case "string":
                        if (isAnchor) { newObj.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(attrName, AttributeType.String)); }
                        else if (isMultivalued) { newObj.Attributes.Add(SchemaAttribute.CreateMultiValuedAttribute(attrName, AttributeType.String)); }
                        else { newObj.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute(attrName, AttributeType.String)); }
                        break;

                    case "integer":
                        if (isAnchor) { newObj.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(attrName, AttributeType.Integer)); }
                        else if (isMultivalued) { newObj.Attributes.Add(SchemaAttribute.CreateMultiValuedAttribute(attrName, AttributeType.Integer)); }
                        else { newObj.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute(attrName, AttributeType.Integer)); }
                        break;

                    case "reference":
                        if (isMultivalued) { newObj.Attributes.Add(SchemaAttribute.CreateMultiValuedAttribute(attrName, AttributeType.Reference)); }
                        else { newObj.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute(attrName, AttributeType.Reference)); }
                        break;

                    case "binary":
                        if (isAnchor) { newObj.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(attrName, AttributeType.Binary)); }
                        else if (isMultivalued) { newObj.Attributes.Add(SchemaAttribute.CreateMultiValuedAttribute(attrName, AttributeType.Binary)); }
                        else { newObj.Attributes.Add(SchemaAttribute.CreateSingleValuedAttribute(attrName, AttributeType.Binary)); }
                        break;

                    case "boolean":
                        if (isAnchor) { newObj.Attributes.Add(SchemaAttribute.CreateAnchorAttribute(attrName, AttributeType.Boolean)); }
                        else { newObj.Attributes.Add(SchemaAttribute.CreateMultiValuedAttribute(attrName, AttributeType.Boolean)); }
                        break;
                }

            }

            schema.Types.Add(newObj);

        }
    }

    public class networkUtils
    {
        // args[0] can be an IPaddress or host name. 
        public bool pingHost(string args)
        {
            try
            {
                Ping pingSender = new Ping();
                PingOptions options = new PingOptions();

                // Use the default Ttl value which is 128, 
                // but change the fragmentation behavior.
                options.DontFragment = true;

                // Create a buffer of 32 bytes of data to be transmitted. 
                string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
                byte[] buffer = Encoding.ASCII.GetBytes(data);
                int timeout = 120;
                PingReply reply = pingSender.Send(args, timeout, buffer, options);
                if (reply.Status == IPStatus.Success) { return true; }
                else { return false; }
            }
            catch (Exception ex)
            { return false; }
        }
    }

}